/**
 * Copyright 2012 Brigham Young University
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package edu.byu.nlp.al;

import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

import edu.byu.nlp.pipes.Annotator;
import edu.byu.nlp.pipes.Instance;

/**
 * An InstanceProvider that assigns the annotator to the next instance that has fewer than K annotations, but has more
 * than other qualifying instances. This implementation does NOT allow the same annotator to annotate the same instance
 * more than once.
 * 
 * @author rah67
 *
 */
public class KAnnotationsInstanceProvider<L, D> implements InstanceManager<L, D> {

	private static final class NumberOfAnnotatorsComparator<L, D> implements Comparator<Instance<L, D>> {

		/** {@inheritDoc} */
		@Override
		public int compare(Instance<L, D> i1, Instance<L, D> i2) {
			return i2.getAnnotations().size() - i1.getAnnotations().size();
		}
		
	}
	
	private final int k;
	private final BlockingQueue<Instance<L, D>> q;
	private final Collection<Instance<L, D>> completed;
	
	@VisibleForTesting
	KAnnotationsInstanceProvider(int k, BlockingQueue<Instance<L, D>> q, Collection<Instance<L, D>> completed) {
		this.k = k;
		this.q = q;
		this.completed = completed;
	}
	
	public static <L, D> KAnnotationsInstanceProvider<L, D> newProvider(int k, Iterable<Instance<L, D>> instances,
			int initialCapacity) {
		BlockingQueue<Instance<L, D>> q =
				new PriorityBlockingQueue<Instance<L,D>>(initialCapacity, new NumberOfAnnotatorsComparator<L, D>());
		Iterables.addAll(q, instances);
		Collection<Instance<L, D>> completed = Lists.newArrayList();
		return new KAnnotationsInstanceProvider<L, D>(k, q, completed);
	}

	/** {@inheritDoc} */
	@Override
	public Instance<L, D> instanceFor(Annotator annotator) {
		// Find the next instance that the specified annotator has NOT annotated
		try {
			Instance<L, D> instance = q.take();
			List<Instance<L, D>> ineligibleInstances = Lists.newArrayList();
			while (!q.isEmpty() && instance.getAnnotations().containsKey(annotator)) {
				ineligibleInstances.add(instance);
				instance = q.take();
			}
			for (Instance<L, D> ineligibleInstance : ineligibleInstances) {
				q.put(ineligibleInstance);
			}
			return instance;
		} catch (InterruptedException e) {
			throw new RuntimeException("Problem getting instance for " + annotator, e);
		}
	}

	/** {@inheritDoc} */
	@Override
	public void UpdateInstance(Instance<L, D> instance, Annotator annotator, L annotation) {
		instance.getAnnotations().put(annotator, annotation);
	}
	
}
